package org.studiox.graph.runtime.service;

import org.apache.commons.lang3.StringUtils;
import org.janusgraph.core.JanusGraph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.studiox.graph.common.GraphLineage;
import org.studiox.graph.common.IGraphWrapper;
import org.studiox.graph.common.exception.GraphException;
import org.studiox.graph.janusgraph.latest.JanusGraphLatest;
import org.studiox.graph.persistence.mybatis.tk.domain.GraphEdgeDO;
import org.studiox.graph.persistence.mybatis.tk.domain.GraphVertexDO;
import org.studiox.graph.persistence.mybatis.tk.service.GraphDbService;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;

@Service
public class GraphService {

  private static final Logger LOGGER = LoggerFactory.getLogger(GraphService.class);

  private IGraphWrapper graphWrapper;

  @Autowired private GraphDbService graphDbService;

  @PostConstruct
  public void init() {
    try {
      graphWrapper = new JanusGraphLatest(LOGGER);
      graphWrapper.open();
    } catch (GraphException e) {
      LOGGER.error(e.getMessage(), e);
    }
  }

  @PreDestroy
  public void clean() {
    if (null != graphWrapper) {
      graphWrapper.close();
    }
  }

  public JanusGraph getJanusGraphInstance() {
    return ((JanusGraphLatest) graphWrapper).getJanusGraph();
  }

  public void addGraphVertex(String unique) {
    if (StringUtils.isBlank(unique)) {
      return;
    }
    Long vertexDbId = graphDbService.getGraphVertexIdByUniq(unique);
    if (null != vertexDbId) {
      return;
    }
    Long vertexGraphId = graphWrapper.createVertex(unique, null, null);
    GraphVertexDO graphVertexDO = new GraphVertexDO();
    graphVertexDO.setUniq(unique);
    graphVertexDO.setJanusVertexId(vertexGraphId);
    graphDbService.insertGraphVertex(graphVertexDO);
  }

  public List<String> getAllGraphVertexUniqueNames() {
    return graphDbService.getGraphVertexUniqs();
  }

  public void addGraphEdge(String content, String sourceUnique, String targetUnique) {
    if (StringUtils.isBlank(content)
        || StringUtils.isBlank(sourceUnique)
        || StringUtils.isBlank(targetUnique)) {
      return;
    }
    List<String> contents = graphDbService.getGraphEdgeContents(sourceUnique, targetUnique);
    if (null == contents || contents.isEmpty()) {
      Long sourceVertexGraphId;
      GraphVertexDO graphVertexDO = graphDbService.getGraphVertexDoByUniq(sourceUnique);
      if (null == graphVertexDO) {
        sourceVertexGraphId = graphWrapper.createVertexNotPreCheck(sourceUnique, null, null);
        graphVertexDO = new GraphVertexDO();
        graphVertexDO.setUniq(sourceUnique);
        graphVertexDO.setJanusVertexId(sourceVertexGraphId);
        graphDbService.insertGraphVertex(graphVertexDO);
      } else {
        sourceVertexGraphId = graphVertexDO.getJanusVertexId();
      }
      Long targetVertexGraphId;
      graphVertexDO = graphDbService.getGraphVertexDoByUniq(targetUnique);
      if (null == graphVertexDO) {
        targetVertexGraphId = graphWrapper.createVertexNotPreCheck(targetUnique, null, null);
        graphVertexDO = new GraphVertexDO();
        graphVertexDO.setUniq(targetUnique);
        graphVertexDO.setJanusVertexId(targetVertexGraphId);
        graphDbService.insertGraphVertex(graphVertexDO);
      } else {
        targetVertexGraphId = graphVertexDO.getJanusVertexId();
      }
      String graphEdgeId =
          graphWrapper.createEdgeNotPreCheck(
              content, null, sourceVertexGraphId, targetVertexGraphId, null);
      GraphEdgeDO graphEdgeDO = new GraphEdgeDO();
      graphEdgeDO.setContent(content);
      graphEdgeDO.setSourceVertexUniq(sourceUnique);
      graphEdgeDO.setTargetVertexUniq(targetUnique);
      graphEdgeDO.setJanusEdgeId(graphEdgeId);
      graphEdgeDO.setSourceJanusVertexId(sourceVertexGraphId);
      graphEdgeDO.setTargetJanusVertexId(targetVertexGraphId);
      graphDbService.insertGraphEdge(graphEdgeDO);
      graphDbService.updateGraphEdgeContentMd5(graphEdgeDO.getId());
    } else if (!contents.contains(content)) {
      GraphEdgeDO graphEdgeDO =
          graphDbService.getOneGraphEdgeDoBySourceTargetUniq(sourceUnique, targetUnique);
      graphEdgeDO.setId(null);
      graphEdgeDO.setContent(content);
      graphEdgeDO.setContentMd5(null);
      graphEdgeDO.setCreateTime(null);
      graphEdgeDO.setUpdateTime(null);
      graphDbService.insertGraphEdge(graphEdgeDO);
    }
  }

  public List<String> getGraphEdgeContentsBySourceTargetUnique(
      String sourceUnique, String targetUnique) {
    return graphDbService.getGraphEdgeContents(sourceUnique, targetUnique);
  }

  public GraphLineage getImpact(String vertexUniq, Integer depth, boolean skipDeleted) {
    return graphWrapper.getImpact(vertexUniq, depth, skipDeleted);
  }

  public GraphLineage getLineage(String vertexUniq, Integer depth, boolean skipDeleted) {
    return graphWrapper.getLineage(vertexUniq, depth, skipDeleted);
  }

  public GraphLineage getFullLineage(String vertexUniq, Integer depth, boolean skipDeleted) {
    return graphWrapper.getFullLineage(vertexUniq, depth, skipDeleted);
  }
}
